/**
 *  防止循环引用:使用 WeakMap 来存储已经拷贝的对象，防止因循环引用导致的无限递归
 *  内存管理：WeakMap 中的键是弱引用，这意味着当没有其他引用指向键时，键值对会被垃圾回收。
 *      使用普通对象或 Map 作为存储结构的话，如果对象的引用链很长，可能会导致内存无法被及时回收，造成内存泄漏。
 *      是弱引用，内存管理更为高效。在处理大量数据或复杂对象时，性能和内存占用是非常重要的考虑因素。
 *  防止意外引用：使用普通对象作为缓存会导致意外的引用保持，从而使得在不需要的情况下仍然占用内存。使用 WeakMap 则不会有这个问题，确保只在需要时保持引用。
 */
function deepClone(obj, hash = new WeakMap()) {
  if (obj === null) return obj;

  if (obj instanceof RegExp) return new RegExp(obj);

  if (obj instanceof Date) return new Date(obj);

  if (obj instanceof Set) {
    let cloneSet = new Set();
    hash.set(obj, cloneSet); // >>
    for (const ele of obj) {
      cloneSet.add(deepClone(ele, hash));
    }
    return cloneSet;
  }

  if (obj instanceof Map) {
    let cloneMap = new Map();
    hash.set(obj, cloneMap); // >>
    for (const [key, value] of obj) {
      cloneMap.set(deepClone(key, hash), deepClone(value, hash)); // >>
    }
    return cloneMap;
  }

  if (Array.isArray(obj)) {
    let cloneArr = [];
    hash.set(obj, cloneArr);
    for (const ele of obj) {
      cloneArr.push(deepClone(ele, hash)); // >>
    }
    return cloneArr;
  }

  if (typeof obj === "function") {
    return obj;
  }

  // >>
  if (typeof obj === "symbol") {
    return Symbol(obj.description);
  }

  if (typeof obj !== "object") {
    return obj;
  }

  if (hash.has(obj)) {
    return hash.get(obj);
  }

  let cloneObj = new obj.constructor();
  hash.set(obj, cloneObj); // >>

  let keys = reflect.ownKeys(obj);
  for (let i in keys) {
    cloneObj[keys[i]] = deepClone(obj[keys[i]], hash); // >>
  }

  let symKeys = Object.getOwnPropertySymbols(obj);
  for (const sym of symKeys) {
    cloneObj[Symbol(sym.description)] = deep(obj[sym], hash); // >>
  }

  return cloneObj;
}
